/*

* Copyright (c) 2007, National University of Singapore (NUS)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without 
* modification, are permitted provided that the following conditions 
* are met:
*
*   * Redistributions of source code must retain the above copyright notice, 
*     this list of conditions,the authors and the following disclaimer.
*   * Redistributions in binary form must reproduce the above copyright notice,
*     this list of conditions,the authors and the following disclaimer in
*     the documentation and/or other materials provided with the distribution.
*   * Neither the name of the university nor the names of its 
*     contributors may be used to endorse or promote products derived from 
*     this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
* POSSIBILITY OF SUCH DAMAGE.
* 
* Author: Wenwei Xue (dcsxw@nus.edu.sg)
*
*/
package psg.servicemanager;

import java.util.*;

/**
 * This class represents a context attribute in a domain and its current value in 
 * a simulated physical space.
 */
public class ContextAttribute {
	
	String name;	// name of the context attribute
	
	String value;	// current value of the attribute	
	
	/**
	 * The list of context attributes currently supported by the PSG simulator.
	 */
	public static String [] attrNames = {
		"name", // the name of an entity (in all context domains)
		"phonePickedUp",
		"tvOn",
		"foodOnTable",
		"personAtDoor",
		"personEating",
		"personDrinking",
		"IP", //7
		"Port",//8
		"preference",
		"speed",//10
		"visitingSpace",
		"location",
		"psgPowerLevel",
		"action",
		"mood",//15
		"isBusy",
		"SOLEConnectivity",//17
		"MACAddress", //18
	};
	
	/**
	 * The list of events currently supported by the PSG simulator.
	 * An event attribute only has two possible values: TRUE or FALSE.
	 */
	public static String [] eventNames = {
		"personInRoom"
	};
	
	/**
	 * This function illustrates how the value of a composite attribute, 
	 * user_profile, can be assigned.
	 * We assume user_profile is the concatenation of three sub-attributes: 
	 * (i) to_do_list, (ii) friend_list, and (iii) shopping_list. 
	 * @return the string representation of the user profile
	 */
	public static String createUserProfile () {
		
		String user_profile = "";
		int id;
	
		id = 1;
		String to_do_list = "";
		to_do_list += "List of things to do:" + "\r\n";
		to_do_list += "[" + "ID: " + String.valueOf(id++) + "\t";
		to_do_list += "Task: " + "Go for shopping" + "\t";
		to_do_list += "Due date: " + currentDate() + "]";
		to_do_list += "\r\n";	
		// more elements can be added to the list if necessary		
		user_profile += to_do_list;
		user_profile += "\r\n";
		
		id = 1;
		String friend_list = "";
		friend_list += "List of friends:" + "\r\n";
		friend_list += "[" + "ID: " + String.valueOf(id++) + "\t";
		friend_list += "Name: " + "Ben" + "]";
		friend_list += "\r\n";
		// more elements can be added to the list if necessary		
		user_profile += friend_list;
		user_profile += "\r\n";
		
		id = 1;
		String shopping_list = "";
		shopping_list += "List of items to buy:" + "\r\n";
		shopping_list += "[" + "ID: " + String.valueOf(id++) + "\t";
		shopping_list += "Item: " + "basket of eggs" + "\t";
		shopping_list += "Quantity: " + "1" + "]";
		shopping_list += "\r\n";
		// more elements can be added to the list if necessary		
		user_profile += shopping_list;	
				
		return user_profile;
		
	}  // createUserProfile
	
	/**
	 * This function returns the current system date in a specific format.
	 * @return the string representation of current system date
	 */
	public static String currentDate() {
		
		Calendar c = Calendar.getInstance();
		String ds = "";
		
		switch (c.get(Calendar.MONTH)) {
		case 0: ds += "January"; break;
		case 1: ds += "February"; break;
		case 2: ds += "March"; break;
		case 3: ds += "April"; break;
		case 4: ds += "May"; break;
		case 5: ds += "June"; break;
		case 6: ds += "July"; break;
		case 7: ds += "August"; break;
		case 8: ds += "September"; break;
		case 9: ds += "October"; break;
		case 10: ds += "November"; break;
		case 11: ds += "December"; break;
		default:
		}
		
		ds += " " + String.valueOf(c.get(Calendar.DATE));
		ds += ", ";
		ds += String.valueOf(c.get(Calendar.YEAR));
		
		return ds;
		
	}  // currentDate
	
	/**
	 * This function extracts the to_do_list sub-field from user_profile.
	 * @return a 2-d String array that contains the Description and Due Date for each task 
	 *         in to_do_list
	 *		   Examples: to_do_list[0][0] = "Go for shopping" (task description)
	 *                   to_do_list[0][1] = "September 18, 2007" (due date of the task)
	 *                   to_do_list[1][0] = "Go to gym" (a second task)
	 *                   to_do_list[1][1] = "September 20, 2007" (due date of the second task)
	 */
	public static String [][] getToDoList (String user_profile) {
		
		String to_do_list [][] = null;
		String str;
		int start, end, mark;
		Vector temp = new Vector (10,5);
		
		start = user_profile.indexOf("List of things to do:");
		if (start == -1)
		{
			to_do_list = new String [1][2];
			to_do_list [0][0] = "To do list is empty.";
			to_do_list [0][1] = currentDate();
			return to_do_list;
		}
		mark = user_profile.indexOf("List of friends:");
		if (mark==-1)
			mark = user_profile.indexOf("List of items to buy:");
		if (mark == -1)
			mark = user_profile.length()-1;
		start += "List of things to do:".length();
		start = user_profile.indexOf("Task:", start);
		if (start == -1)
		{
			to_do_list = new String [1][2];
			to_do_list [0][0] = "To do list is empty.";
			to_do_list [0][1] = currentDate();
			return to_do_list;
		}
		while (start != -1) {
			start += "Task:".length();
			end = user_profile.indexOf("Due date:", start);
			if (end == -1)
			{
				to_do_list = new String [1][2];
				to_do_list [0][0] = "Invalid format of to do list.";
				to_do_list [0][1] = currentDate();
				return to_do_list;
			}
			str = "";
			str += user_profile.substring(start, end).trim();
			temp.addElement((String)str);
			start = end + "Due date:".length();
			end = user_profile.indexOf("]",start);
			if (end >= mark || end==-1)
			{
				to_do_list = new String [1][2];
				to_do_list [0][0] = "Invalid format of to do list.";
				to_do_list [0][1] = currentDate();
				return to_do_list;
			}
			str = "";
			str += user_profile.substring(start,end).trim();
			temp.addElement((String)str);
			start = user_profile.indexOf("Task:", start);
			if (start >= mark) break; 	
		}
		
		to_do_list = new String [temp.size()/2][2];
	    int i =0;
		for (int j=0;j<temp.size()/2;j++)
			for (int k=0;k<2;k++)
				to_do_list[j][k] = (String)temp.elementAt(i++);			
				
		return to_do_list;
				
	}  // getToDoList
	
	/**
	 * This function extracts the friend_list sub-field from user_profile.
	 * @return a 1-d String array that contains the name of each friend
	 *         in friend_list
	 *		   Examples: friend_list[0] = "Ben"
	 *                   friend_list[1] = "Tom"
	 *                   friend_list[2] = "Jim"
	 */
	public static String [] getFriendList (String user_profile) {
		
		String friend_list [] = null;
		String str;
		int start, end, mark;
		Vector temp = new Vector (10,5);
		
		start = user_profile.indexOf("List of friends:");
		if (start == -1)
		{
			friend_list = new String [1];
			friend_list [0] = "Friend list is empty.";
			return friend_list;
		}
		mark = user_profile.indexOf("List of items to buy:");
		if (mark == -1)
			mark = user_profile.length()-1;
		start += "List of friends:".length();
		start = user_profile.indexOf("Name:", start);
		if (start == -1)
		{
			friend_list = new String [1];
			friend_list [0] = "Friend list is empty.";
			return friend_list;
		}
		while (start != -1) {
			start += "Name:".length();
			end = user_profile.indexOf("]", start);
			if (end == -1 || end>mark)
			{
				friend_list = new String [1];
				friend_list [0] = "Invalid format of friend list.";
				return friend_list;
			}
			str = "";
			str += user_profile.substring(start, end).trim();
			temp.addElement((String)str);
			start = user_profile.indexOf("Name:", end);
			if (start >= mark) break; 	
		}
		
		friend_list = new String [temp.size()];
	    for (int i=0;i<temp.size();i++)
	    	friend_list[i] = (String)temp.elementAt(i);		
				
		return friend_list;	
				
	}  // getFriendList
	
	/**
	 * This function extracts the shopping_list sub-field from user_profile.
	 * @return a 2-d String array that contains the Description and Quantity for each item
	 *         in shopping_list
	 *		   Examples: shopping_list[0][0] = "basket of eggs" (item description)
	 *                   shopping_list[0][1] = "1" (quantity of the item to purchase)
	 */
	public static String [][] getShoppingList (String user_profile) {
		
		String shopping_list [][] = null;
		String str;
		int start, end, mark;
		Vector temp = new Vector (10,5);
		
		start = user_profile.indexOf("List of items to buy:");
		if (start == -1)
		{
			shopping_list = new String [1][2];
			shopping_list [0][0] = "Shopping list is empty.";
			shopping_list [0][1] = currentDate();
			return shopping_list;
		}
		mark = user_profile.length()-1;
		start += "List of items to buy:".length();
		start = user_profile.indexOf("Item:", start);
		if (start == -1)
		{
			shopping_list = new String [1][2];
			shopping_list [0][0] = "Shopping list is empty.";
			shopping_list [0][1] = currentDate();
			return shopping_list;
		}
		while (start != -1) {
			start += "Task:".length();
			end = user_profile.indexOf("Quantity:", start);
			if (end == -1)
			{
				shopping_list = new String [1][2];
				shopping_list [0][0] = "Invalid format of shopping list.";
				shopping_list [0][1] = currentDate();
				return shopping_list;
			}
			str = "";
			str += user_profile.substring(start, end).trim();
			temp.addElement((String)str);
			start = end + "Quantity:".length();
			end = user_profile.indexOf("]",start);
			if (end >= mark || end==-1)
			{
				shopping_list = new String [1][2];
				shopping_list [0][0] = "Invalid format of shopping list.";
				shopping_list [0][1] = currentDate();
				return shopping_list;
			}
			str = "";
			str += user_profile.substring(start,end).trim();
			temp.addElement((String)str);
			start = user_profile.indexOf("Item:", start);
			if (start >= mark) break; 	
		}
		
		shopping_list = new String [temp.size()/2][2];
	    int i =0;
		for (int j=0;j<temp.size()/2;j++)
			for (int k=0;k<2;k++)
				shopping_list[j][k] = (String)temp.elementAt(i++);			
				
		return shopping_list;
				
	}  // getShoppingList
	
	/**
	 * This function assigns a default value to a context attribute.
	 * @param name of the context attribute
	 * @return default value assigned to the attribute
	 */
	public static String assignDefaultValue(String name) {
		
		name = name.toLowerCase();
		
		if (name.equals(attrNames[0].toLowerCase()))
			return "no_name";
		
		// - MODIFICATION[I2R]
		for (int j=1; j<attrNames.length; j++){
			if (name.equals(attrNames[j].toLowerCase())){
				return "false";
			}
		}

		
		int i;
		for (i=0;i<eventNames.length;i++)
			if (name.equals(eventNames[i].toLowerCase()))
				break;
		if (i!=eventNames.length)
			return "false";
		
		return null;
		
	}  // assignDefaultValue
	
	/**
	 * This function examines whether a given name for a context attribute is valid.
	 * @param name a given name
	 * @return TRUE if the input is a valid name for some context attribute; otherwise FALSE
	 */
	public static boolean checkName(String name) {
		
		name = name.toLowerCase();
		
		int i;
		for (i=0;i<attrNames.length;i++)
			if (name.toLowerCase().equals(attrNames[i].toLowerCase()))
				return true;
		for (i=0;i<eventNames.length;i++)
			if (name.toLowerCase().equals(eventNames[i].toLowerCase()))
				return true;
				
		return false;
		
	}
	
	/**
	 * This function examines whether a given value for a context attribute is valid.
	 * @param name name of a context attribute
	 * @param value a given value for the attribute
	 * @return TRUE if the value is valid for the attribute; otherwise FALSE
	 */
	public static boolean checkValue(String name, String value) {
		
		/*
		name = name.toLowerCase();
		
		if (name.equals(attrNames[0].toLowerCase()))
			return true; // name can be any string
		else if (name.equals(attrNames[1].toLowerCase()))
			   if (value.toLowerCase().equals("no_meeting") || value.toLowerCase().equals("meeting_in_progress"))
			     return true;
			   else
			   	 return false;
		else if (name.equals(attrNames[2].toLowerCase()) || name.equals(attrNames[5].toLowerCase()))
			   return true;  // location can by any string
		else if (name.equals(attrNames[3].toLowerCase()))
				{
					boolean empty = true;
					String to_do_list [][] = getToDoList(value);
					if (to_do_list[0][0].equals("Invalid format of to do list."))
						return false;
					if (!to_do_list[0][0].equals("To do list is empty."))
						empty = false;					
					String friend_list [] = getFriendList(value);
					if (friend_list[0].equals("Invalid format of friend list."))
						return false;
					if (!friend_list[0].equals("Friend list is empty."))
						empty = false;
					String shopping_list [][] = getShoppingList(value);
					if (shopping_list[0][0].equals("Invalid format of shopping list."))
						return false;
					if (!shopping_list[0][0].equals("Shopping list is empty."))
						empty = false;
					// System.out.println(empty);
					if (empty & !value.equals(""))
						return false;
					return true;
				}
		else if (name.equals(attrNames[4].toLowerCase()))
			   if (value.toLowerCase().equals("low") || value.toLowerCase().equals("high") || value.toLowerCase().equals("modest"))
			   	 return true;
			   else
			   	 return false;
		else if (name.equals(attrNames[6].toLowerCase()))
				{
					try {Double.parseDouble(value);}
			   		catch (Exception e) {return false;}
			   		
			   		return true;	// price must be a valid real number
				}
		
		int i;
		for (i=0;i<eventNames.length;i++)
			if (name.equals(eventNames[i].toLowerCase()))
				break;
		if (i!=eventNames.length && (value.toLowerCase().equals("true") || value.toLowerCase().equals("false")))
			return true;
	    else
	    	return false;
	   */
		return true;
	}	// checkValue	

	// debugging purpose
	/*public static void main (String argvs []) {
	
		String user_profile = createUserProfile();
		System.out.println(user_profile);
		String to_do_list [][] = getToDoList(user_profile);
		for (int i=0;i<to_do_list.length;i++)
			for (int j=0;j<to_do_list[0].length;j++)
				System.out.println(to_do_list[i][j]);
		String friend_list [] = getFriendList(user_profile);
		for (int i=0;i<friend_list.length;i++)
			System.out.println(friend_list[i]);
		String shopping_list [][] = getShoppingList(user_profile);
		for (int i=0;i<shopping_list.length;i++)
			for (int j=0;j<shopping_list[0].length;j++)
				System.out.println(shopping_list[i][j]);
				
	}  // main*/
	
}  // class